<?php

namespace App\Services\Call;

use App\Actions\PaycallAction;
use App\Constants\CodeData;
use App\Dao\AnchorDao;
use App\Dao\ClosenessDao;
use App\Dao\CommonSettingDao;
use App\Dao\FollowListDao;
use App\Dao\PayCallDao;
use App\Dao\UserBlacklistDao;
use App\Dao\UserDao;
use App\Dao\UserRemarkDao;
use App\Exception\MessageException;
use App\Model\Anchor;
use App\Model\PayCall;
use App\Model\CallShow;
use App\Model\User;
use App\Model\UserCardPack;
use App\Services\PushMessageService;
use App\Services\YunXinCloud\WyyClientService;
use App\Utils\FunUtil;
use App\Utils\MemcacheClient;
use App\Utils\MongoDBClient;
use App\Utils\RedisClient;
use Hyperf\Context\Context;
use function Hyperf\Config\config;
use function Hyperf\Translation\trans;

class CallService
{

    /**
     * Note - 对另一方发起视频语音呼叫
     * DateTime 2024/7/26 11:38
     * User Admin
     * @param array $params
     * @param $userInfo
     * @return array
     */
    public function call(array $params, $userInfo)
    {
        $uid = $userInfo['id'];
        $user_id = $params['user_id'];
        $is_call_mass = $params['is_call_mass'] ?? 0; // 1-表示来自心动匹配;0-表示用户普通呼叫
        $type = $params['type']; // 1-视频;2-语音
        $match_id = $params['match_id'] ?? 0; // 心动匹配ID
        $from = $params['from'] ?? 1;
        $version_code = $params['version_code'] ?? 0;
        $card_id = $params['card_id'] ?? 0;
        $ip = FunUtil::getClientIp();

        $redis = RedisClient::getInstance();

        if ($userInfo['sex'] == 2) {
            $is_anchor = true;
            $userId = $user_id;
            $anchorId = $uid;
            // 等级对应每天可以拨打的次数
            $callConfig = [
                '4' => 50,
                '3' => 20,
                '2' => 10,
                '1' => 5
            ];

            $closeness = ClosenessDao::read($userId, $anchorId);
            // 请密度不够时，等级对应每天可以拨打的次数
            if ($closeness < 5 && $is_call_mass == 0) {
                if ($userInfo['push_level'] > 0) {
                    $count = $redis->get("white_user_call_count_{$anchorId}") ?: 0;
                    if ($count >= $callConfig[$userInfo['push_level']]) {
                        throw new MessageException('双方亲密度需要达到1级才可以开启视频通话功能。对方回复您或者给您送礼物可以快速提升亲密度~', CodeData::NEED_TIPS);
                    } else {
                        $redis->set("white_user_call_count_{$anchorId}", $count + 1, strtotime(date("Y-m-d") . " 23:59:59") - time());
                    }
                } else {
                    throw new MessageException('双方亲密度需要达到1级才可以开启视频通话功能。对方回复您或者给您送礼物可以快速提升亲密度~', CodeData::NEED_TIPS);
                }
            }
        } else {
            $is_anchor = false;
            $userId = $uid;
            $anchorId = $user_id;
        }

        // 判断对方是否在你黑名单中
        // 或者你是否在对方黑名单中
        $black_list = UserBlacklistDao::getInstance()->getBlackUids($uid);
        if (in_array($user_id, $black_list)) {
            throw new MessageException('你已拉黑对方或对方已拉黑你', CodeData::NEED_TIPS);
        }

        if (in_array($user_id, UserDao::getInstance()->getDisturbList())) {
            throw new MessageException('对方已开启勿扰模式', CodeData::NEED_TIPS);
        }

        if ($userInfo['sex'] == 1) {
            $caller = 1;
            $channel = $userInfo['channel'];
            list($price, $anchor_info, $user_info, $accept_language, $tmp, $card_id) = $this->checkManCall($userId, $anchorId, $type, $is_call_mass, $card_id, $params);
        } else {
            //发起方是女主播
            $caller = 2;
            $channel = $userInfo['channel'];
            if (strripos($userInfo['head_image'], 'default/headimg/woman.') !== false || empty($userInfo['head_image'])) {
                throw new MessageException('请上传头像!', CodeData::NEED_TIPS, ['result' => 1]);
                // Tool::JSON(\CodeData::JUMP_EDIT_PROFILE, array('result' => 1), '请重新上传头像!');
            }
            list($price, $anchor_info, $user_info, $accept_language, $tmp, $card_id) = $this->checkFemaleCall($userId, $anchorId, $type, $is_call_mass, $card_id, $params);
        }

        $closeness = ClosenessDao::read($userId, $anchorId);

        // 风险用户拨打伪装
        $is_limit = FunUtil::chatLimit($userId, $anchorId, $closeness);
        if ($is_limit
            || ($userInfo['sex'] == 2 && $userInfo['guild_num'] == 'yq00154')
        ) {
            $retval = [
                'call_id' => 1,
                'channelKey' => "",
                'token' => '',
                'channelName' => 1,//房间号
                'free_video' => 0,
                'gift_divide_rate' => '0.4',
                'free_video_time' => 0,
                'super_free_video_time' => 0,
                'is_concern' => FollowListDao::getInstance()->checkIsFans($uid, $user_id) ? 1 : 0,
                'closeness' => $closeness,
                'card_id' => $card_id
            ];
            // 风险用户伪装拨打成功
            return formatData($retval, 200, 200, '正在接通中...');
            // Tool::JSON(\CodeData::SUCCESS, array('result' => 1, 'msg' => $retval), '正在接通中...');
        }
        if (!MemcacheClient::getInstance()->add('call_call_frequency_' . $uid, 1, 5)) {
            throw new MessageException('你太心急了，休息一会再来吧', CodeData::NEED_TIPS, ['result' => 3]);
            // Tool::JSON(\CodeData::NEED_TIPS, array('result' => 3), '你太心急了，休息一会再来吧');
        }
        //创建通话记录
        $rate = (float)$anchor_info['rate'];
        $insertData = array(
            'anchor_id' => $anchorId,
            'user_id' => $userId,
            'type' => $type,
            'start_time' => 0,//看情况要不要先设置
            'end_time' => 0,
            'price' => $price,
            'anchor_account' => $anchor_info['gift_count'],
            'user_coin' => $user_info['gift_count'] + $user_info['sys_send_count'] + $user_info['recharge_send_count'],
            'rate' => $rate,
            'status' => 0,
            'ctime' => time(),
            'caller' => $caller,
            'extend' => '',
            'from' => $from,
            'version_code' => $version_code,
            'channel' => $channel,
            'guild_num' => $userInfo["guild_num"],
            'ip' => $ip,
            'match_id' => $match_id,
            'is_call_mass' => $is_call_mass == 1 ? 1 : 0,
            'free_video' => 0,
            'card_id' => $card_id
        );
        $call_id = PayCall::query()->insertGetId($insertData);
        // 视频速聊价格修改
        $call_price = 0;
        if ($is_call_mass && $from == 1) {
            $call_price = $price;
            if (!$is_anchor) {
                $call_price = $price * $anchor_info["rate"];
            }
        }
        MemcacheClient::getInstance()->delete('last_pay_call_item_' . $anchorId);
        MemcacheClient::getInstance()->delete('last_pay_call_item_' . $userId);

        //对方处于在线并且空闲状态，可以呼叫。插入到mongo
        $remark = UserRemarkDao::getInstance()->getInfo($userId, $anchorId);
        $monInsertData = array();
        $monInsertData['uid'] = (int)$uid; //发送方
        $monInsertData['receive_uid'] = (int)$user_id;   //接收方
        $monInsertData['content'] = !empty($remark) ? $remark['remarks_name'] . trans('message.想和你通话', [], $accept_language) : $userInfo['nickname'] . trans('message.想和你通话', [], $accept_language);
        $monInsertData['ctime'] = time();
        $monInsertData['chat_type'] = $is_call_mass == 1 ? 10 : 7;  //新类型
        $monInsertData['content_type'] = $type == 1 ? 4 : 5; // 4：视频通话请求，5：语音通话请求
        $monInsertData['from'] = $from;
        $call_data = [
            'video_price' => $anchor_info['video_price'],
            'audio_price' => $anchor_info['audio_price'],
            'call_price' => (string)$call_price,
            'call_type' => $type,
            'gift_count' => $user_info['gift_count'] + $user_info['sys_send_count'] + $user_info['recharge_send_count'],
            'call_id' => $call_id,
            'is_call_mass' => $is_call_mass,
            'card_id' => $card_id
        ];
        $caller == 1 && $call_data['video_price'] = $anchor_info['video_price'] * $anchor_info['rate'];
        $call_data['earns'] = $price * $anchor_info['rate'];
        $call_data['spends'] = $price;

        $monInsertData['call_data'] = json_encode($call_data);
        $monInsertData['look'] = 0;  //是否已读
        $monInsertData['date'] = date("Y-m-d");
        $monInsertData['free_video'] = 0;
        // 是否是新人
        $monInsertData['is_new_user'] = UserDao::getInstance()->checkNewUser($uid);
        $monInsertData['is_recommend'] = $caller == 2 ? $anchor_info['is_recommend'] : 0;

        // $mongo = new MonDB();
        // $mongo->selectCollection(MON_USER_CHAT);
        $mongo = MongoDBClient::getInstance();
        $mongo->insert('tb_user_chat_v2', $monInsertData);

        //网易云 音视频
        $token = (new WyyClientService)->getTokenYunXin($uid, $call_id);

        $retval = [
            'call_id' => $call_id,
            'channelKey' => "",
            'token' => $token,
            'channelName' => $call_id,//房间号
            'free_video' => 0,
            'gift_divide_rate' => $rate,
            'free_video_time' => 0,
            'super_free_video_time' => 0,
            'is_concern' => FollowListDao::getInstance()->checkIsFans($uid, $user_id) ? 1 : 0,
            'closeness' => $closeness,
            'card_id' => $card_id
        ];
        // 通话的话费和收入
        $retval['earns'] = $call_data['earns'];
        $retval['spends'] = $call_data['spends'];

        // 表明自己在线
        PayCallDao::getInstance()->keepAliveStatus($uid, $call_id);

        // if ($retval['call_id'] > 0 && !empty($retval['token'])) {
        if ($user_id > 0) {
            if ($userInfo['sex'] == 1) {
                $package = $tmp['package'];
            } else {
                $package = $user_info['package'];
            }
            // (new Push())->putPushMsgQueue($user_id, $userInfo['nickname'] . ':[' . trans('message.请求与你通话',[],$accept_language) . ']', $package);
            // 加入友盟消息推送队列
            PushMessageService::putUMengMsgQueue($user_id, $userInfo['nickname'] . ':[' . trans('message.请求与你通话', [], $accept_language) . ']', $package);
        }
        PushMessageService::putYunXinCallMsgQueue($uid, [$user_id]);

        return formatData(array('result' => 1, 'msg' => $retval), 200, 200, '正在接通中...');
        // Tool::JSON(\CodeData::SUCCESS, array('result' => 1, 'msg' => $retval), '正在接通中...');
        // } else {
        //     // Tool::JSON(\CodeData::NEED_TIPS, '', '网络繁忙，请稍后再试');
        //     throw new MessageException('网络繁忙，请稍后再试', CodeData::NEED_TIPS);
        // }

    }


    /**
     * Note -
     * DateTime 2024/7/25 17:47
     * User Admin
     * @param $userId // 用户id
     * @param $anchorId // 主播id
     * @param $type // 1 视频通话 2 语音通话
     * @param $is_call_mass // 1-表示来自心动匹配；0-表示用户普通呼叫
     * @param $card_id // 体验卡
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    private function checkManCall($userId, $anchorId, $type, $is_call_mass, $card_id, $params)
    {
        //说明发起方是男用户
        $anchor_info = AnchorDao::getInstance()->findAnchorInfoById($anchorId);
        if ($anchor_info['status'] != 0) {
            throw new MessageException('对方暂时无法接听', CodeData::NEED_TIPS);
        }
        $price = ($type == 1) ? $anchor_info['video_price'] : $anchor_info['audio_price'];

        // 113版本之后 视频速聊默认价格30金币
        if ($is_call_mass && $params['from'] == 1) {
            $price = 30;
        }

        // 获取主播的信息
        $tmp = User::query()->where('id', $anchorId)->first();
        $tmp = modelToArray($tmp);
        $ext2 = json_decode($tmp['ext2'], true);
        $accept_language = $ext2['language'] ?? 'en';
        // 收费版
        if (CHARGE_CALL_VERSION) {
            // 使用体验卡判断
            $times = strtotime(date("Ymd"));
            $cardCount = CommonSettingDao::getValue('woman_card_count', 10);    // 女用户体验卡上限
            if ($card_id > 0) {
                // $cardData = $userModel->find('*', "id=? and uid=? and card_type=? and status=?", [$card_id, $uid, 1, 0], "", "tb_user_card_pack");
                $cardData = UserCardPack::query()->where('id', $card_id)->where('uid', $userId)->where('card_type', 1)->where('status', 0)->first();
                if (empty($cardData)) {
                    throw new MessageException("可用体验卡不足", CodeData::NEED_TIPS);
                }

                // $useCard = $userModel->find('*', "uid=? and card_type=? and status=1 and use_time>?", [$uid, 1, $times], "", "tb_user_card_pack");
                $useCard = UserCardPack::query()->where('uid', $userId)->where('card_type', 1)->where('status', 1)->where('use_time', '>', $times)->first();
                if (!empty($useCard)) {
                    throw new MessageException("每日限使用一张体验卡", CodeData::NEED_TIPS);
                }

                // 女用户体验卡上限
                // $anchorCardCount = $userModel->findOneField("select count(*) today_card from tb_user_card_pack where uid={$anchorId} and get_time>{$times}", "today_card") ?: 0;
                $anchorCardCount = UserCardPack::query()->where('uid', $anchorId)->where('get_time', '>', $times)->count();
                if ($anchorCardCount >= $cardCount) {
                    throw new MessageException("今日女用户体验卡通话已达上限，继续呼叫将按对方设置费用付费~", CodeData::NEED_TIPS);
                    // Tool::JSON(\CodeData::SUCCESS, array('result' => 5), '今日女用户体验卡通话已达上限，继续呼叫将按对方设置费用付费~');
                }

            } else {
                // 匹配也可以用体验卡
                // 没有选择体验卡，判断有可用卡直接使用
                // $cardData = $payCallModel->find('*', "uid=? and card_type=? and status=?", [$uid, 1, 0], "", "tb_user_card_pack");
                $cardData = UserCardPack::query()->where('uid', $userId)->where('card_type', 1)->where('status', 0)->first();

                if (!empty($cardData)) {
                    $card_id = $cardData['id'];
                    // $useCard = $payCallModel->find('*', "uid=? and card_type=? and status=1 and use_time>?", [$uid, 1, strtotime(date("Ymd"))], "", "tb_user_card_pack");
                    $useCard = UserCardPack::query()->where('uid', $userId)->where('card_type', 1)->where('status', 1)->where('use_time', '>', $times)->first();
                    if (!empty($useCard)) {
                        // 每日限使用一张体验卡
                        $card_id = 0;
                    } else {
                        // $anchorCardCount = $userModel->findOneField("select count(*) today_card from tb_user_card_pack where uid={$anchorId} and get_time>{$times}", "today_card") ?: 0;
                        $anchorCardCount = UserCardPack::query()->where('uid', $anchorId)->where('get_time', '>', $times)->count();
                        if ($anchorCardCount >= $cardCount) {
                            $card_id = 0;
                        }
                    }
                }
            }
        }
        $user_info = User::find($userId)->toArray();

        $anchor_info['gift_count'] = $tmp['gift_count'];

        //判断用户余额gift_count + 系统赠送金币
        if ($user_info['gift_count'] + $user_info['sys_send_count'] + $user_info['recharge_send_count'] < $price && $card_id == 0 && CHARGE_CALL_VERSION) {
            throw new MessageException("呀~余额不足了呢~", CodeData::NEED_TIPS, ['result' => -1]);
            // Tool::JSON(\CodeData::NEED_TIPS, array('result' => -1), '呀~余额不足了呢~');
        }

        if ($tmp['online'] == 0) {
            throw new MessageException("对方已下线，您可以给TA留言或去首页撩其他有缘人", CodeData::NEED_TIPS, ['result' => -1]);
            // Tool::JSON(\CodeData::NEED_TIPS, array('result' => -1), '对方已下线，您可以给TA留言或去首页撩其他有缘人');
        }

        // $myItem = $payCallModel->getLastItemByUid($userId, false, true);
        $myItem = PayCallDao::getInstance()->getLastItemByUid($userId, false, true);
        if (!empty($myItem) && $myItem['status'] == 0 && $myItem['end_time'] == 0) {
            // 用户自己还有未完成的通话，立刻结束，防止锁住主播
            // $payCallModel->updateByWhere(array("status" => 1, "extend" => '1'), "id = {$myItem['id']} and status=0");
            PayCall::query()->where('id', $myItem['id'])->where('status', 0)->update(['status' => 1, 'extend' => '1']);
        }

        $status = PayCallDao::getInstance()->checkIsCalling($anchorId);
        if ($status) {
            if (!$tmp['hide_call_status']) {
                throw new MessageException("正在通话中，要不要先去看下TA的照片？", CodeData::NEED_TIPS, ['result' => 0]);
                // Tool::JSON(\CodeData::NEED_TIPS, array('result' => 0), '正在通话中，要不要先去看下TA的照片？');
            }
        }
        return [
            $price,
            $anchor_info,
            $user_info,
            $accept_language,
            $tmp,
            $card_id
        ];
    }


    /**
     * Note -
     * DateTime 2024/7/25 17:51
     * User Admin
     * @param $userId // 用户ID
     * @param $anchorId // 主播ID
     * @param $type // 1 视频 2 语音
     * @param $is_call_mass // 1-表示来自心动匹配；0-表示用户普通呼叫
     * @param $card_id // 体验卡
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \RedisException
     */
    private function checkFemaleCall($userId, $anchorId, $type, $is_call_mass, $card_id)
    {

        $anchor_info = AnchorDao::getInstance()->findAnchorInfoById($anchorId);
        if ($anchor_info['status'] != 0) {
            throw new MessageException('已被限制使用', CodeData::NEED_TIPS);
            // Tool::JSON(\CodeData::NEED_TIPS, '', '已被限制使用');
        }
        $price = $type == 1 ? $anchor_info['video_price'] : $anchor_info['audio_price'];

        // 113版本之后 视频速聊默认价格30金币
        if ($is_call_mass && Context::get('cvf')['from'] == 1) {
            $price = 30;
        }

        // 用户信息
        $user_info = User::query()->where('id', $userId)->first();
        $user_info = modelToArray($user_info);
        $ext2 = json_decode($user_info['ext2'], true);
        $accept_language = $ext2['language'] ?? 'en';

        // 主播信息
        $tmp = User::query()->where('id', $anchorId)->first();
        $tmp = modelToArray($tmp);
        $anchor_info['gift_count'] = $tmp['gift_count'];

        if ($user_info['online'] == 0) {
            throw new MessageException("对方已下线，您可以给TA留言或去首页撩其他有缘人", CodeData::NEED_TIPS, ['result' => -1]);
            // Tool::JSON(\CodeData::SUCCESS, array('result' => -1), '对方已下线，您可以给TA留言或去首页撩其他有缘人');
        }

        if ($user_info['sex'] == 2) {
            throw new MessageException('已被限制使用', CodeData::NEED_TIPS);
            // Tool::JSON(\CodeData::NEED_TIPS, '', '已被限制使用');
        }

        // 1-表示来自心动匹配；0-表示用户普通呼叫
        if ($is_call_mass == 0) {
            // 高频呼叫5分钟限制
            $anchorCallSign = RedisClient::getInstance()->get("call_limit_{$anchorId}_{$userId}");
            if ($anchorCallSign) {
                // Tool::JSON(\CodeData::NEED_TIPS, ['result'=>0], '您短时间内对 '.$anchorCallSign.' 进行高频呼叫，被限制5分钟之内无法使用主动呼叫!');
                throw new MessageException('因高频呼叫，5分钟之内无法使用主动呼叫!', CodeData::NEED_TIPS, ['result' => 0]);
                // Tool::JSON(\CodeData::NEED_TIPS, ['result' => 0], '因高频呼叫，5分钟之内无法使用主动呼叫!');
            }

            $lastCallSign = RedisClient::getInstance()->get("call_{$anchorId}_{$userId}");
            if ($lastCallSign == 2) {
                // 上次该用户通话挂断不超过5秒 再次发起呼叫触发5分钟呼叫限制
                RedisClient::getInstance()->setex("call_limit_{$anchorId}_{$userId}", 5 * 60, $user_info['nickname']);
                // Tool::JSON(\CodeData::NEED_TIPS, ['result'=>0], '您短时间内对 '.$user_info['nickname'].' 进行高频呼叫，被限制5分钟之内无法使用主动呼叫!');
                // Tool::JSON(\CodeData::NEED_TIPS, ['result' => 0], '因高频呼叫，5分钟之内无法使用主动呼叫!');
                throw new MessageException('因高频呼叫，5分钟之内无法使用主动呼叫!', CodeData::NEED_TIPS, ['result' => 0]);
            }
        }

        // 收费版
        if (CHARGE_CALL_VERSION) {
            // 女用户发起，判断是否可用户体验卡，判断对方是否有体验卡
            // 女用户体验卡上限
            $times = strtotime(date("Ymd"));
            // $anchorCardCount = $userModel->findOneField("select count(*) today_card from tb_user_card_pack where uid={$anchorId} and get_time>{$times}", "today_card") ?: 0;
            $anchorCardCount = UserCardPack::query()->where('uid', $anchorId)->where('get_time', '>', $times)->count();
            $cardCount = CommonSettingDao::getValue('woman_card_count', 10);
            if ($anchorCardCount < $cardCount) {
                // $cardData = $payCallModel->find('*', "uid=? and card_type=? and status=?", [$userId, 1, 0], "", "tb_user_card_pack");
                $cardData = UserCardPack::query()->where('uid', $userId)->where('card_type', 1)->where('status', 0)->first();

                if (!empty($cardData)) {
                    $card_id = $cardData['id'];
                    // $useCard = $payCallModel->find('*', "uid=? and card_type=? and status=1 and use_time>?", [$userId, 1, $times], "", "tb_user_card_pack");
                    $useCard = UserCardPack::query()->where('uid', $userId)->where('card_type', 1)->where('status', 1)->where('use_time', '>', $times)->first();
                    if (!empty($useCard)) {
                        $card_id = 0;
                    }
                }
            }
        }


        $myItem = PayCallDao::getInstance()->getLastItemByUid($anchorId, true, true);
        if (!empty($myItem) && $myItem['status'] == 0) {
            //主播自己还有未完成的通话，立刻结束，防止锁住用户
            if ($myItem['end_time'] == 0) {
                // $payCallModel->updateByWhere(array("status" => 1, "extend" => '2'), "id = {$myItem['id']} and status=0");
                PayCall::query()->where('id', $myItem['id'])->where('status', 0)->update(['status' => 1, 'extend' => '2']);

            } else {
                $paycallAction = new PaycallAction();
                $paycallAction->getProfitForCall($myItem, true);
                // $payCallModel->updateByWhere(array("status" => 1, "extend" => '2'), "id = {$myItem['id']} and status=0");
                PayCall::query()->where('id', $myItem['id'])->where('status', 0)->update(['status' => 1, 'extend' => '2']);

            }
        }

        $status = PayCallDao::getInstance()->checkIsCalling($userId, false);
        if ($status) {
            throw new MessageException("正在通话中，要不要先去看下TA的照片？", CodeData::NEED_TIPS, ['result' => 0]);
            // Tool::JSON(\CodeData::SUCCESS, array('result' => 0), '正在通话中，要不要先去看下TA的照片？');
        }

        return [
            $price,
            $anchor_info,
            $user_info,
            $accept_language,
            $tmp,
            $card_id
        ];

    }


    /**
     * Note - 获取匹配的用户
     * DateTime 2024/8/19 19:43
     * User Admin
     * @param mixed $userInfo
     * @param $params
     * @return array
     */
    public function getMatchingUsers(mixed $userInfo, $params)
    {
        $uid = $userInfo['id'];
        $match_id = $params['match_id'] ?? sprintf("%s_%s", $uid, getMillisecond());
        $call_type = $params['call_type']; // 1-视频 2-语音

        if ($userInfo['sex'] == 2) {
            if (strripos($userInfo['head_image'], 'default/headimg/woman.') !== false || empty($userInfo['head_image'])) {
                // Tool::JSON(\CodeData::NEED_TIPS, array('result' => 1), '请重新上传头像!');
                throw new MessageException('请重新上传头像!', CodeData::NEED_TIPS, ['result' => 1]);
            }
            [$total, $data] = (new CallUserService())->matchMales($match_id, $uid, $call_type);
        } else {
            if ($userInfo['noble'] != 1 && $userInfo['super_noble'] != 1) {
                $redis = RedisClient::getInstance();
                $hangUpCount = $redis->get("free_call:hang_up_$uid");
                if ($hangUpCount && $hangUpCount >= 5) {
                    // Tool::JSON(\CodeData::NEED_TIPS, array('result' => 5), '请开通会员后重试');
                    throw new MessageException('请开通会员后重试', CodeData::NEED_TIPS, ['result' => 5]);
                }
            }
            [$total, $data] = (new CallUserService())->matchFemales($match_id, $uid, $call_type);
        }

        $rs['result'] = 1;
        $rs['match_id'] = $match_id;
        $rs['total'] = $total;
        if ($call_type == 1) {
            $data['call_price'] = config('custom.video_price');
            $field = 'video_price';
        } else {
            $data['call_price'] = config('custom.audio_price');
            $field = 'audio_price';
        }
        if ($userInfo['sex'] == 2) {
            $info = Anchor::query()->where('uid', $uid)->first([$field, 'rate']);
            $data['call_price'] = $info[$field] * $info['rate'];
        }
        $rs['list'] = $data;
        // Tool::JSON(\CodeData::SUCCESS, $rs, 'success');
        return formatData($rs);
    }


    /**
     * Note - 获取通话列表
     * DateTime 2024/8/19 19:43
     * User Admin
     * @param mixed $userInfo
     * @param $params
     * @return array
     */
    public function getCallList(mixed $userInfo, $params)
    {
        $uid = $userInfo['id'];
        $page = $params['page'] ?? 1;
        $pagesize = $params['pagesize'] ?? 20;
        $language = $params['language'];

        $updateWhere[] = ['is_read', '=', 0];
        if ($userInfo['sex'] == 1) {
            //男
            $updateWhere[] = ['user_id', '=', $uid];
            $updateWhere[] = ['caller', '=', 2];
            $query = PayCall::query()->from('tb_pay_call AS p')
                ->join('tb_user u', 'p.anchor_id', '=', 'u.id')
                ->where('p.user_id', $uid);
        } else {
            $updateWhere[] = ['anchor_id', '=', $uid];
            $updateWhere[] = ['caller', '=', 1];
            $query = PayCall::query()->from('tb_pay_call AS p')
                ->join('tb_user AS u', 'p.user_id', '=', 'u.id')
                ->where('p.anchor_id', $uid)->where('p.is_robot', 0);
        }
        $field = "p.id,p.ctime,case when u.is_disturb=1 and u.online>0 then 4 when u.hide_call_status=1 and u.online=2 then 1 else `online` end as `online`,`type`,u.noble,extend,caller,start_time,end_time,anchor_id,p.type call_type,u.id AS user_id,fare,profit,u.nickname,u.head_image,u.inviteUid";


        // $list = $paycallModel->findAll($field, $where, $bindVal, $join, $order, $limit);
        $list = $query->selectRaw($field)
            ->orderByRaw('ctime DESC')
            ->skip(($page - 1) * $pagesize)
            ->take($pagesize)
            ->get()->toArray();

        $records = [];
        if (!empty($list)) {
            foreach ($list as $v) {
                $record["id"] = intval($v["id"]);
                $record["type"] = intval($v["type"]);
                $record["duration"] = $v["end_time"] - $v["start_time"];
                $record["time_len"] = $v["end_time"] - $v["start_time"];
                if ($userInfo['sex'] == 1) {  //男
                    $record["duration"] = $v["end_time"] - $v["start_time"] + 1;
                }
                if ($v['end_time'] <= 0) {
                    switch ($v["extend"]) {
                        case 61:// 男用户挂断
                            if ($v["caller"] == 2) {
                                if ($userInfo['sex'] == 2) {
                                    $v['extend'] = 2;
                                    $v['extend_t'] = trans("message.对方拒接");
                                } else {
                                    $v['extend'] = 2;
                                    $v['extend_t'] = trans("message.已拒接");
                                }
                            } else {    // 主播挂断
                                if ($userInfo['sex'] == 2) {
                                    $v['extend'] = 2;
                                    $v['extend_t'] = trans("message.已拒接");
                                } else {
                                    $v['extend'] = 2;
                                    $v['extend_t'] = trans("message.对方拒接");
                                }
                            }
                            break;
                        case 41:// 主播取消
                            if ($userInfo['sex'] == 2) {
                                $v['extend'] = 2;
                                $v['extend_t'] = trans("message.已取消");
                            } else {
                                $v['extend'] = 2;
                                $v['extend_t'] = trans("message.对方取消");
                            }
                            break;
                        case 1:
                        case 2:
                            if ($v["caller"] == 2) {// 主播发起
                                if ($userInfo['sex'] == 2) {
                                    $v['extend'] = 2;
                                    $v['extend_t'] = trans("message.无人接通");
                                } else {
                                    $v['extend'] = 3;
                                    $v['extend_t'] = trans("message.未接来电");
                                }
                            } else {// 用户发起
                                if ($userInfo['sex'] == 2) {
                                    $v['extend'] = 3;
                                    $v['extend_t'] = trans("message.未接来电");
                                } else {
                                    $v['extend'] = 2;
                                    $v['extend_t'] = trans("message.无人接通");
                                }
                            }
                            break;
                        case 31:// 用户取消
                            if ($userInfo['sex'] == 2) {
                                $v['extend'] = 2;
                                $v['extend_t'] = trans("message.对方取消");
                            } else {
                                $v['extend'] = 2;
                                $v['extend_t'] = trans("message.已取消");
                            }
                            break;
                        default:
                            $v['extend'] = 3;
                            $v['extend_t'] = trans("message.无人接通");
                            break;
                    }
                } else {
                    $v['extend'] = 1;
                    $v['extend_t'] = trans("message.已接通");
                }

                $record["user_id"] = $v['user_id'];
                $record["vip"] = $v['noble'];
                $record["online"] = $v['online'];
                $record["extend"] = $v['extend'];
                $record["call_type"] = $v['call_type'];
                $record["extend_t"] = $v['extend_t'];
                $record["head_image"] = $v['head_image'];
                $record["user_name"] = $v['nickname'];
                $record["start_time"] = intval($v["start_time"]);
                $record["end_time"] = intval($v["end_time"]);
                $record["ctime"] = formatTime($v["ctime"], $language);
                $record["fare"] = intval($v["fare"]);
                $record["profit"] = intval($v["profit"]);
                $record["time_len"] = formatSecond($record["time_len"]);
                $records[] = $record;
            }
        }

        // 修改状态为已读
        // $paycallModel->updateByWhere(['is_read' => 1], $updateWhere);
        PayCall::where($updateWhere)->update(['is_read' => 1]);

        // Tool::JSON(\CodeData::SUCCESS, array('records' => $records), 'success');
        return formatData(['records' => $records]);
    }


    /**
     * Note - 获取、设置通话封面
     * DateTime 2024/7/26 11:38
     * User Admin
     * @param $uid
     * @param $params
     * @return array
     */
    public function callCover($uid, $params)
    {
        $show = CallShow::query()->where('uid', $uid)->first();
        $request_type = $params['request_type'];
        if ($request_type) {// 上传
            $url = $params['url'];
            // 视频
            $type = 1;
            $header = get_headers($url, 1);
            if (in_array($header['Content-Type'], ['image/png', 'image/jpg', 'image/jpeg', 'image/gif', 'image/webp'])) {
                $type = 2;    // 图片
            }
            if (empty($show)) {
                CallShow::query()->insert(['uid' => $uid, 'url' => $url, 'type' => $type, 'status' => 1, 'ctime' => time()]);
            } else {
                CallShow::query()->where('uid', $uid)->update(['url' => $url, 'type' => $type, 'status' => 1, 'utime' => time()]);
            }
            return formatData(['result' => 1], 200, 200, '提交成功，等待审核通过！');
        } else {
            if (empty($show)) {
                return formatData([], 200, CodeData::NO_PROMPT);
            } else {
                $anchorInfo = Anchor::query()->where('uid', $uid)->first(['call_show', 'call_show_type']);
                $show['call_show'] = $anchorInfo['call_show'];
                $show['call_show_type'] = $anchorInfo['call_show_type'];
                return formatData(['result' => 1, 'msg' => $show]);
            }
        }
    }


    /**
     * Note - 接听方拒绝接听，通知服务器通知发起方
     * DateTime 2024/8/21 14:06
     * User Admin
     * @param mixed $userInfo
     * @param mixed $params
     * @return array
     */
    public function refuse(mixed $userInfo, mixed $params)
    {
        $uid = $userInfo['id'];
        $user_id = intval($params['user_id']); // 被挂断的用户id
        $call_id = intval($params['call_id']); // 本次通话唯一标示
        $overtime = isset($params['overtime']) ? intval($params['overtime']) : 0;

        if ($userInfo['sex'] == 1) {
            //说明是男用户挂断
            $userId = $uid;
            $anchorId = $user_id;
        } else {
            //说明是女主播挂断
            $userId = $user_id;
            $anchorId = $uid;
        }

        // $payCallModel = new PayCallModel();
        // $paycall = $payCallModel->getCallCache($call_id, true);
        $paycall = PayCallDao::getInstance()->getCallCache($call_id, true);
        if (empty($paycall)) {
            // Tool::JSON(\CodeData::NEED_TIPS, '', '通话不存在');
            // return formatData(['result' => 1, 'msg' => '通话不存在']);
            throw new MessageException('通话不存在');
        }

        if ($paycall['anchor_id'] != $anchorId || $paycall['user_id'] != $userId) {
            // Tool::JSON(\CodeData::NEED_TIPS, '', '通话不存在');
            throw new MessageException('通话不存在');
        }


        // 主播发起，用户挂断
        if ($paycall['caller'] == 2 && $paycall['user_id'] == $uid) {
            $redis = RedisClient::getInstance();
            $sign = $redis->get("call_{$paycall['anchor_id']}_{$uid}");
            if ($sign == 1) {
                $redis->set("call_{$paycall['anchor_id']}_{$uid}", 2, 15);
            } else {
                // 通话挂断标识
                $redis->set("call_{$paycall['anchor_id']}_{$uid}", 1, 15);
            }
        }

        if ($paycall['status'] == 0) {
            if ($paycall['start_time'] == 0) {
                // $payCallModel->updateByWhere(array('status' => 1, 'extend' => 61, 'call_wait_time' => intval(time() - $paycall['ctime'])), "id = $call_id and status = 0");
                PayCall::query()->where(['id' => $call_id, 'status' => 0])->update(['status' => 1, 'extend' => 61, 'call_wait_time' => intval(time() - $paycall['ctime'])]);
                MemcacheClient::getInstance()->delete('the_pay_call_' . $call_id);
                MemcacheClient::getInstance()->delete('last_pay_call_item_' . $anchorId);
            } else {
                (new PaycallAction())->hangUpCall($call_id, $uid);
            }
        }

        // 插入mongo，告诉发送方我拒接了
        if ($overtime == 0) {
            // 是否机器人拨打 0：不是 1：是
            if ($paycall['is_robot'] != 1) {
                (new PaycallAction())->sendRefuseMsg($uid, $user_id, $call_id, $paycall['is_call_mass'], $paycall['type']);
            }
        } else {
            (new PaycallAction())->sendUnAnswerMsg($uid, $user_id, $call_id, $paycall['is_call_mass'], $paycall['type']);
        }

        if ($userInfo['sex'] == 1) {
            //说明是男用户
            FunUtil::socket_client('new_user_reject', $uid, $params['session_id'], array('anchor_id' => $user_id));
        }

        // Tool::JSON(\CodeData::SUCCESS, array('result' => 1, 'content_type' => 4), '放弃接听...');
        return formatData(['result' => 1, 'content_type' => 4], 200, 200, '放弃接听...');
    }


    /**
     * Note - 接听方接听，通知服务器
     * DateTime 2024/8/21 15:15
     * User Admin
     * @param mixed $userInfo
     * @param mixed $params
     * @return array
     */
    public function answer(mixed $userInfo, mixed $params)
    {
        $uid = $userInfo['id'];
        $from = intval($params['from']);
        $version_code = intval($params['version_code']);
        $channel = trim($params['channel']);
        $user_id = intval($params['user_id']); //拨打方
        $call_id = intval($params['call_id']); //本次通话唯一标示
        $ip = FunUtil::getClientIp();

        // 禁言判断
        if (FunUtil::gagUserChat($uid)) {
            throw new MessageException("账号异常正在风险审核中，审核通过才可以使用该功能，请耐心等候。");
        }

        if ($userInfo['sex'] == 1) {
            //说明接听方是男用户
            $userId = $uid;
            $anchorId = $user_id;
            $extend_flag = 0;
        } else {
            if (strripos($userInfo['head_image'], 'default/headimg/woman.') !== false || empty($userInfo['head_image'])) {
                // Tool::JSON(\CodeData::NEED_TIPS, array('result' => 1), '请重新上传头像!');
                throw new MessageException('请重新上传头像!');
            }

            //说明接听方是女主播
            $userId = $user_id;
            $anchorId = $uid;
            $extend_flag = 10;
        }

        // $payCallModel = new PayCallModel();
        $paycall = PayCallDao::getInstance()->getCallCache($call_id, true);
        if (empty($paycall)) {
            //Tool::JSON(\CodeData::NEED_TIPS, '', '通话不存在');
            throw new MessageException('通话不存在');
        }
        if ($paycall['anchor_id'] != $anchorId || $paycall['user_id'] != $userId) {
            //Tool::JSON(\CodeData::NEED_TIPS, '', '通话不存在.');
            throw new MessageException('通话不存在');
        }

        // 是否机器人拨打 0：不是 1：是
        if ($paycall['is_robot'] == 1) {
            // $payCallModel->updateByWhere(array('status' => 1, 'extend' => 31 + $extend_flag), "id = $call_id and status = 0");
            PayCall::query()->where(['id' => $call_id, 'status' => 0])->update(['status' => 1, 'extend' => 31 + $extend_flag]);
            MemcacheClient::getInstance()->delete('the_pay_call_' . $call_id);
            MemcacheClient::getInstance()->delete('last_pay_call_item_' . $anchorId);
            $desc = '抱歉，你来的太晚了，对方已挂断';
            $paycall['is_call_mass'] > 0 && $desc = '没有用户接听，请耐心等待';
            // Tool::JSON(\CodeData::NEED_TIPS, '', $desc);
            throw new MessageException($desc);
        }

        if ($paycall['status'] == 1) {
            $desc = '抱歉，你来的太晚了，对方已挂断';
            $paycall['is_call_mass'] > 0 && $desc = '没有用户接听，请耐心等待';
            // Tool::JSON(\CodeData::NEED_TIPS, '', $desc);
            throw new MessageException($desc);
        }

        $card_id = $paycall['card_id'];
        if ($userInfo['sex'] == 1) {
            if ($userInfo['gift_count'] + $userInfo['sys_send_count'] + $userInfo['recharge_send_count'] < $paycall['price'] && $card_id == 0) {
                // Tool::JSON(\CodeData::NEED_TIPS, '', '您的金币余额不足');
                // return formatData([], 200, 200, '您的金币余额不足');
                throw new MessageException('您的金币余额不足');
            }
        }
        $wyyClientService = new WyyClientService();
        $token = $wyyClientService->getTokenYunXin($uid, $call_id);

        //表明自己接听 在线
        PayCallDao::getInstance()->keepAliveStatus($uid, $call_id);

        //把接听方的from、version_code、channel、ip也记录进去
        $answer_info = array(
            'f' => $from,
            'v' => $version_code,
            'c' => $channel,
            'i' => $ip
        );
        $answer_info = json_encode($answer_info);
        // $payCallModel->updateByWhere(array('card_id' => $card_id, 'ext' => $answer_info, 'call_wait_time' => intval(time() - $paycall['ctime'])), "id = $call_id");
        PayCall::query()->where(['id' => $call_id])->update(['card_id' => $card_id, 'ext' => $answer_info, 'call_wait_time' => intval(time() - $paycall['ctime'])]);

        // 接通后给对方发送消息通知
        (new PaycallAction())->sendAnswerMsg($uid, $user_id, $call_id, $paycall['is_call_mass'], $paycall['type']);
        // 检查是否关注
        $is_concern = FollowListDao::getInstance()->checkIsFans($uid, $user_id);
        return formatData([
            'result' => 1,
            'msg' => [
                'call_id' => $call_id,
                'channelKey' => '',
                'token' => $token,
                'channelName' => $call_id,
                'gift_divide_rate' => $paycall['rate'],
                'is_concern' => $is_concern ? 1 : 0,
                'free_video_time' => 0,
                'super_free_video_time' => 0
            ]
        ], 200, CodeData::SUCCESS, '接听成功...');

        // Tool::JSON(\CodeData::SUCCESS, array('result' => 1, 'msg' =>
        //     array('call_id' => $call_id,
        //         'channelKey' => '',
        //         'token' => $token,
        //         'channelName' => $call_id,
        //         'gift_divide_rate' => $paycall['rate'],
        //         'is_concern' => $is_concern ? 1 : 0,
        //         'free_video_time' => 0, 'super_free_video_time' => 0)
        // ), '接听成功...');

    }


    /**
     * Note - 挂断通话
     * DateTime 2024/8/21 15:51
     * User Admin
     * @param mixed $userInfo
     * @param mixed $params
     * @return array
     */
    public function hangUp(mixed $userInfo, mixed $params)
    {
        $uid = $userInfo['id'];
        $call_id = intval($params['call_id']);
        // 风险用户拨打伪装,假装挂断
        if ($call_id == 1) {
            throw new MessageException("无人接听");
        }
        return (new PaycallAction())->hangUpCall($call_id, $uid);
        // return formatData([], 200, CodeData::NEED_TIPS, '通话已挂断');

    }

}